<?php if(!defined('SYSPATH')) die('Not define SYSPATH');
/**
 * 自动加载器
 *
 * @author fakis738@gmail.com
 * @link http://www.woophp.com/manual/class/loader.php
 * @version $id loader.lib.php v0.1 2011-12-03$
 */
class Loader
{
    /**
     * 自动加载主路径
     * @access protected
     * @type string $path
     */
    protected $path = '';

    /**
     * 统计加载次数
     * @access public
     * @type int $count
     */
    public $count = 0;

    /**
     * 加载文件是否为类文件，如果为类文件则类名
     * @access protected
     * @type string $class
     */
	protected $class = '';

    /**
     * 解析主路径
     * @access protected
     * @type array $parse
     */
	protected $parse = array();

    /**
     * 已加载文件
     * @access protected
     * @type array $loaded
     */
	protected $loaded = array();

    /**
     * 自动查找继承目录
     * @access protected
     * @type array $findPaths
     */
	protected $findPaths = array();

    /**
     * 自动查找本地路径
     * @access protected
     * @type array $includeDir
     */
	protected $includeDir = array();

    /**
     * 如果为类文件，实例化对象
     * @access protected
     * @type object $instantiated
     */
    protected $instantiated = NULL;

    /**
     * 构造方法
     * @access public
     */
    public function __construct()
    {
        $this->includeDir = WS::CFG('loader_include_dir');
    }
	
    /**
     * 路径解析器
     * @access protected
     * @param string $path
     * @return void
     */
    protected function parser($path)
    {
        if(!preg_match('/^((\w+)[\/\w+]*\/)(\w+[\.\w+]*)\.(\w+){1,4}$/', $path, $m))
            WS::ERR('自动加载路径错误 path: '. $path);

        $this->path = $m[0];
        $this->parse['dir']  = $m[1];
        $this->parse['mode'] = $m[2];
        $this->parse['node'] = $m[3];
        $this->parse['ext']  = $m[4];

        $this->findAllPaths($this->parse['node']);
    }

    /**
     * 迭代所有层级继承路径，数组倒序
     * @access protected
     * @param string $node
     */
    protected function findAllPaths($node)
    {
        if(FALSE === strpos($node, '.'))
        {
            $this->findPaths[] = $this->parse['dir']. $node. '.'. $this->parse['ext'];
            $this->findPaths = array_reverse($this->findPaths);
        }
        else
        {
            $this->findPaths[] = $this->parse['dir']. $node. '.'. $this->parse['ext'];
            $hex = substr($node, 0, strrpos($node, '.'));
            $this->findAllPaths($hex);
        }
    }

    /**
     * 根据路径取得类名
     * @access protected
     * @param stirng $path
     * @return stirng $classname
     */
    protected function getClassname($path)
    {
        $arr = preg_split('/\b(\w+)\b/', $path, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
        $classname = '';
        foreach($arr as $key => $val)
        {
            $classname .= ucfirst($val);
        }
        $classname = str_replace(array('_', '/', '.'), array('__', '_', '_To_'), $classname);

        return $classname;
    }

    /**
     * 加载文件
     * @access protected
     * @param stirng $path
     * @param stirng $option
     * @return stirng $classname
     */
    protected function load($path, $option=0)
    {
        global $_LOAD;

        $is_load = FALSE;
        //改变查找路径顺序
        if(in_array($option, array(1, 3))) krsort($this->includePath);
        //查找文件并加载
        foreach($this->includeDir as $dir)
        {
            //如果文件不存在，跳出本次循环
            if(!is_file($dir. $path))
                continue;

            require_once($dir. $path);
            $is_load = TRUE;
            //加载文件完整路径
            $this->loaded[] = $dir. $path;
            $class = $this->parse['dir']. $this->parse['node'];
            if(class_exists($this->getClassname($class)))
                $this->class = $this->getClassname($class);

            //加载多文件
            if(!in_array($option, array(2, 3)))
                break;
        }
        if(!$is_load)
            return FALSE;

        $_LOAD[$path] = $this;
        return $_LOAD[$path];
    }

    /**
     * 开始自动加载
     * @access public
     * @param string $path
     */
    public function auto($path)
    {
        global $_LOAD;
        if(isset($_LOAD[$path]) && is_object($_LOAD[$path]))
        {
            $_LOAD[$path]->count++;
            return $_LOAD[$path];
        }

        $this->parser($path);
        foreach($this->findPaths as $ipath)
        {
            if(!$this->load($ipath))
                WS::ERR('没有找到文件 '. $ipath);
        }

        $this->count++;
        return $_LOAD[$path];
    }

    /**
     * 实例化主类
     * @access public
     * @param string $params
     * @return object
     */
    public function init($params=NULL)
    {
        $class = $this->class;
        if(is_object($this->instantiated))
            return $this->instantiated;

        if(empty($class) || !class_exists($class))
            WS::ERR('没有找到类');

        $this->instantiated = new $class($params);
        return $this->instantiated;
    }

    /**
     * 将已加载类克隆别名，并实例化对象
     * @access public
     * @param array $params
     * @return object
     */
    public function create($alias, $params=NULL)
    {
        global $_LOAD;
        if(isset($_LOAD[$alias]) && is_object($_LOAD[$alias]))
        {
            return $_LOAD[$alias]->init($params);
        }

        $_LOAD[$this->path]->count--;
        $_LOAD[$alias] = clone($_LOAD[$this->path]);
        $_LOAD[$alias]->count = 1;
        return $_LOAD[$alias]->init($params);
    }

    public function alias($alias)
    {
        global $_LOAD;
        if(isset($_LOAD[$alias]) && !empty($_LOAD[$alias]->instantiated))
        {
            $_LOAD[$this->path]->count--;
            $_LOAD[$alias]->count++;
            return $_LOAD[$alias]->instantiated;
        }
        return FALSE;
    }

    public function remove($alias)
    {
        global $_LOAD;
        if(isset($_LOAD[$alias]))
        {
            $_LOAD[$this->path]->count--;
            unset($_LOAD[$alias]);
        }
    }
}
